package controllers

import (
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"

	"cashew.com/cashew_api/dtos"
	"cashew.com/cashew_api/services"
	"cashew.com/cashew_common/configs"
	"cashew.com/cashew_common/constants"
)

type FileController struct {
	BaseController
}

func (c *FileController) Upload() {

	userId := c.GetString("user_id")
	key := c.GetString("key")
	c.Info("上传文件: ", userId, key)

	if userId == "" || key == "" {
		c.Error("参数错误: ", userId, key)
		c.Result(constants.ERR_PARAM, nil)
		return
	}

	maxSize := configs.UploadMaxSize

	if maxSize == 0 {
		c.Error("获取文件上限配置失败: ", userId)
		c.Result(constants.ERR_SYS, nil)
	}

	// 限制最大上传文件大小为 5MB
	maxUploadSize := maxSize * 1024 * 1024

	// 获取文件和文件头
	file, fileHeader, err := c.GetFile("file")
	if err != nil {
		c.Error("获取文件失败: ", err)
		c.Result(constants.ERR_FILE_UPLOAD_FAIL, nil)
		return
	}
	defer func(file multipart.File) {
		err = file.Close()
		if err != nil {
			c.Error("关闭文件失败: ", err)
		}
	}(file)

	// 创建一个 io.LimitedReader 限制文件读取大小
	limitedReader := &io.LimitedReader{
		R: file,
		N: maxUploadSize + 1, // 限制为 MaxUploadSize + 1，用于检查是否超出
	}

	// 读取文件数据（这里只验证大小，不实际保存）
	buffer := make([]byte, maxUploadSize+1)
	n, err := io.ReadFull(limitedReader, buffer)
	if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
		c.Error("读取文件失败: ", err)
		c.Result(constants.ERR_FILE_UPLOAD_FAIL, nil)
		return
	}

	// 检查文件是否超出大小限制
	if int64(n) > maxUploadSize {
		c.Error("文件超出大小限制: ", n)
		c.Result(constants.ERR_FILE_TOO_LARGE, nil)
		return
	}

	// 获取文件类型
	fileNameExt := filepath.Ext(fileHeader.Filename)
	fileNameExt = fileNameExt[1:]

	// 保存文件到指定路径
	var basePath, extPath string
	basePath, extPath, err = services.GetUploadPath(key, fileNameExt)

	if err != nil {
		c.Error("获取文件保存路径失败: ", err)
		c.Result(constants.ERR_SYS, nil)
		return
	}

	fileName := services.GenerateUploadFileName(key, fileNameExt)

	if fileName == "" {
		c.Error("生成文件名失败: ", err)
		c.Result(constants.ERR_SYS, nil)
	}

	savePath := fmt.Sprintf("%s/%s", basePath, extPath)
	saveFile := fmt.Sprintf("%s/%s", savePath, fileName)
	localPath := fmt.Sprintf("/%s/%s", extPath, fileName)

	url, err := services.GetUploadUrl(localPath)

	if err != nil {
		c.Error("获取文件URL失败: ", err)
		c.Result(constants.ERR_SYS, nil)
		return
	}

	if err = os.MkdirAll(savePath, os.ModePerm); err != nil {
		c.Error("创建文件夹失败: ", err)
		c.Result(constants.ERR_SYS, nil)
		return
	}

	destFile, err := os.Create(saveFile)

	if err != nil {
		c.Error("创建文件失败: ", err)
		c.Result(constants.ERR_SYS, nil)
		return
	}
	defer destFile.Close()

	// 重新打开文件并写入到目标文件中
	_, err = destFile.Write(buffer[:n])
	if err != nil {
		c.Error("写入文件失败: ", err)
		c.Result(constants.ERR_SYS, nil)
		return
	}

	res := dtos.FileUploadResult{
		Url:  url,
		File: localPath,
	}

	c.Result(constants.SUCCESS, res)
}
